package com.zhny.aiot.zbsyb.sexual.trap.plugin;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhny.aiot.plugin.ICenterFacilities;
import com.zhny.aiot.plugin.IDeviceFactory;
import com.zhny.aiot.plugin.core.utils.MessageUtils;
import com.zhny.aiot.plugin.model.DeviceEntity;
import com.zhny.aiot.plugin.model.MessageEntry;
import com.zhny.aiot.plugin.model.MessageType;
import com.zhny.aiot.plugin.model.TaskEntity;
import com.zhny.aiot.plugin.web.WebDevice;
import com.zhny.aiot.zbsyb.sexual.trap.plugin.model.SexualTrapStoreEntry;
import com.zhny.aiot.zbsyb.sexual.trap.plugin.result.SexualTrapData;
import com.zhny.aiot.zbsyb.sexual.trap.plugin.result.SexualTrapToken;
import com.zhny.aiot.zbsyb.sexual.trap.plugin.result.SexualTrapUserInfo;
import io.netty.util.internal.StringUtil;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.pf4j.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SexualTrapDevice extends WebDevice<SexualTrapConfig> {

    private static final Logger log=LoggerFactory.getLogger (SexualTrapStoreEntry.class);
    private SexualTrapToken token;
    private Long deviceId;


    public SexualTrapDevice(IDeviceFactory<SexualTrapConfig> factory, ICenterFacilities centerFacilities, DeviceEntity entity) {
        super (factory, centerFacilities, entity);
    }

    @Override
    protected void onRequestHttp(TaskEntity taskEntity, CloseableHttpClient closeableHttpClient) {
        if(isTokenExpires ()) {
            this.token=onTokenHttp (closeableHttpClient);
        }
        onConfigResponse (closeableHttpClient);
        successResponse (closeableHttpClient);
    }

    private boolean isTokenExpires() {
        if(token == null)
            return true;
        Long oldTimeStamp=token.getTime ();
        Long currentTimeStamp=System.currentTimeMillis ();
        Long expires=86400L;
        if(((currentTimeStamp-oldTimeStamp) / 1000)>=expires)
            return true;
        return false;
    }

    private SexualTrapToken onTokenHttp(CloseableHttpClient httpClient) {
        log.info ("execute sexual trap soil api token request!");
        URIBuilder uriBuilder=null;
        SexualTrapConfig config=this.getConfig ();
        if(StringUtils.isNullOrEmpty (config.getHost ()))
            return null;
        String host=config.getHost ().contains ("http://") ? config.getHost () : "http://"+config.getHost ();

        try {
            uriBuilder=new URIBuilder (host+"/loginFree");
            Map<String, Object> param=new HashMap<String, Object> () {{
                put ("username", config.getUserName ());
                put ("password", config.getPassword ());
            }};
            HttpPost httpPost=new HttpPost (uriBuilder.build ());
            String requestBody=serialize (param);
            if(StringUtils.isNullOrEmpty (requestBody))
                return null;
            httpPost.setEntity (new StringEntity (requestBody));
            httpPost.addHeader ("Content-Type", "application/json");
            try (CloseableHttpResponse response=httpClient.execute (httpPost)) {
                String body=EntityUtils.toString (response.getEntity ());
                SexualTrapToken newToken=mapTo (body, new TypeReference<SexualTrapToken> () {
                });
                if(newToken == null)
                    throw new RuntimeException ("sexual trap token api result map to error !");
                newToken.setTime (System.currentTimeMillis ());
                return newToken;
            } catch (ClientProtocolException e) {
                throw new RuntimeException (e);
            } catch (ConnectTimeoutException e) {
                throw new RuntimeException ("请求连接超时");
            } catch (IOException e) {
                throw new RuntimeException (e);
            }
        } catch (URISyntaxException e) {
            throw new RuntimeException (e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException (e);
        }
    }

    private void onConfigResponse(CloseableHttpClient httpClient) {
        log.info ("read sexual trap config api response!");
        URIBuilder uriBuilder=null;
        SexualTrapConfig config=this.getConfig ();
        if(StringUtils.isNullOrEmpty (config.getHost ()))
            throw new RuntimeException ("sexual trap host is null !");
        if(StringUtils.isNullOrEmpty (config.getSn ()))
            throw new RuntimeException ("sexual trap sn is null !");
        if(this.token == null) {
            throw new RuntimeException ("sexual trap token is null !");
        }
        String host=config.getHost ().contains ("http://") ? config.getHost () : "http://"+config.getHost ();
        try {
            String httpUrl=host+"/permi/getAllPermiList";
            uriBuilder=new URIBuilder (httpUrl);
            HttpGet httpGet=new HttpGet (uriBuilder.build ());
            httpGet.addHeader ("Authorization", this.token.getToken ());
            try (CloseableHttpResponse response=httpClient.execute (httpGet)) {
                String body=EntityUtils.toString (response.getEntity ());
                SexualTrapUserInfo result=mapTo (body, new TypeReference<SexualTrapUserInfo> () {
                });
                if(result == null) {
                    log.error ("{}sexual trap config api result map to error !", this.getDeviceEntity ().getName ());
                    return;
                }
                onSetMap (result.getData (), config.getSn ());
            } catch (ClientProtocolException e) {
                throw new RuntimeException (e);
            } catch (ConnectTimeoutException e) {
                throw new RuntimeException ("请求连接超时");
            } catch (IOException e) {
                throw new RuntimeException (e);
            }
        } catch (URISyntaxException e) {
            throw new RuntimeException (e);
        }
    }

    private void onSetMap(JSONObject data, String deviceNo) {
        if(data.containsKey ("device_permi")) {
            JSONArray array=data.getJSONArray ("device_permi");
            for (int i=0; i<array.size (); i++){
                JSONObject item=array.getJSONObject (i);
                if(item.containsKey ("manualId")) {
                    String id=item.getString ("manualId");
                    if(id.equals (deviceNo)) {
                        this.deviceId=item.getLong ("deviceId");
                        return;
                    }
                }
            }
        }
    }


    private void successResponse(CloseableHttpClient httpClient) {
        log.info ("execute sexual trap soil api data request!");
        URIBuilder uriBuilder=null;
        SexualTrapConfig config=this.getConfig ();
        String deviceName = config.getSn ();
        if(StringUtils.isNullOrEmpty (config.getHost ()))
            throw new RuntimeException ("sexual trap host is null !");
        if(this.token == null) {
            throw new RuntimeException ("sexual trap no login !");
        }
        if(StringUtils.isNullOrEmpty (deviceName)) {
            throw new RuntimeException ("sexual trap no found deviceName !");
        }
        String host=config.getHost ().contains ("http://") ? config.getHost () : "http://"+config.getHost ();
        try {
            uriBuilder=new URIBuilder (host+"/inducePest/info/getInfoByCondition");
            HttpPost httpPost=new HttpPost (uriBuilder.build ());
            httpPost.addHeader ("Authorization", this.token.getToken ());
//            httpPost.addHeader ("Content-Type", "multipart/form-data");
            MultipartEntityBuilder entityBuilder=MultipartEntityBuilder.create ();
            ContentType contentType=ContentType.create ("text/plain", Charset.forName ("UTF-8"));
            entityBuilder.addTextBody ("pageNum", "1", contentType);
            entityBuilder.addTextBody ("pageSize", "1", contentType);
            entityBuilder.addTextBody ("deviceId", String.valueOf (this.deviceId), contentType);
            entityBuilder.addTextBody ("AscOrDesc", "true", contentType);
            httpPost.setEntity (entityBuilder.build ());
            try (CloseableHttpResponse response=httpClient.execute (httpPost)) {
                String body=EntityUtils.toString (response.getEntity ());
                SexualTrapData result=mapTo (body, new TypeReference<SexualTrapData> () {
                });
                if(result != null) {
                    MessageEntry messageEntry=MessageUtils.createMessageEntry (this.getId ());
                    messageEntry.setType (MessageType.RESULT);
                    if(result.getRows ().size () == 0)
                        return;
                    SexualTrapStoreEntry entry=getStoreEntry (result);
                    if(entry != null) {
                        messageEntry.setData (entry);
                        nofity (messageEntry);
                        save (entry);
                        saveReal (entry);
                    }
                }

            } catch (ClientProtocolException e) {
                throw new RuntimeException (e);
            } catch (ConnectTimeoutException e) {
                throw new RuntimeException ("请求连接超时");
            } catch (IOException e) {
                throw new RuntimeException (e);
            }
        } catch (URISyntaxException e) {
            throw new RuntimeException (e);
        }
    }

    private <T> T mapTo(String body, TypeReference<T> cls) {
        if(StringUtil.isNullOrEmpty (body))
            return null;
        ObjectMapper mapper=new ObjectMapper ();
        try {
            mapper.configure (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            T obj=mapper.readValue (body, cls);
            return obj;
        } catch (IOException e) {
            return null;
        }
    }

    private String serialize(Object obj) {
        if(obj == null)
            return null;
        ObjectMapper mapper=new ObjectMapper ();
        try {
            return mapper.writeValueAsString (obj);
        } catch (IOException e) {
            return null;
        }
    }

    private SexualTrapStoreEntry getStoreEntry(SexualTrapData result) {
        SexualTrapStoreEntry entry=new SexualTrapStoreEntry ();
        JSONObject object=result.getRows ().getJSONObject (0);
        if(StringUtils.isNullOrEmpty (this.getConfig ().getHost ()))
            return null;
        if(object == null)
            return null;
        if(object.containsKey ("imgPest")) {
            entry.setImgPest (object.getString ("imgPest"));
        }
        if(object.containsKey ("url")) {
            entry.setResultUrl (this.getConfig ().getHost ()+object.getString ("url"));
        }
        return entry;
    }
}
